package simplechat.client;

import simplechat.util.MessageUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @program: netty-study
 * @description: 客户端处理类
 * @author: 胡海龙
 * @create: 2021-04-10 22:13:54
 **/
public class ClientUserHandle implements Runnable {

    private final String serverHost;  //中心服务器IP地址
    private final Integer serverPort;  //中心服务器端口
    private final String fromName;  //自己的用户名
    private Selector selector;  //多路复用器
    private SocketChannel socketChannel;
    private volatile boolean stop;

    /**
     * 初始化构造函数
     *
     * @param serverHost 服务器IP地址
     * @param serverPort 服务器端口
     */
    public ClientUserHandle(String serverHost, Integer serverPort, String fromName) {
        this.serverHost = serverHost;
        this.serverPort = serverPort;
        this.fromName = fromName;
        try {
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void readMessage(ByteBuffer buffer, SocketChannel channel) throws IOException {
        int readBytes = channel.read(buffer);
        while (readBytes != -1 && readBytes != 0) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);
                String receiveMessage = new String(bytes, StandardCharsets.UTF_8);
                if("login success".equals(receiveMessage)){
                    System.out.println(receiveMessage);
                    return;
                }
                Map<String, String> map = MessageUtil.getInfoByMessage(receiveMessage);
                String sendName = map.get("sendName");
                String sendMessage = map.get("sendMessage");
                System.out.println(sendName + " : " + sendMessage);
            }
            buffer.clear();
            readBytes = channel.read(buffer);
        }
    }

    private void handleReceiveMessage(SelectionKey key) throws IOException {
        //首先判断key是否有效
        if (key.isValid()) {
            //判断是否连接成功,如果连接成功发送消息
            if (key.isConnectable()) {
                if (socketChannel.finishConnect()) {
                    System.out.println("connection server is succeed");
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    writeMessage(socketChannel,"hello to server");
                } else {
                    System.out.println("connection server is failed");
                    System.exit(1);
                }
            }
            if (key.isReadable()) {
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                readMessage(readBuffer, socketChannel);
                sendMessage(socketChannel);
            }
        }
    }

    /**
     * 连接服务器
     *
     * @throws IOException some exception
     */
    private void connectServer() throws IOException {
        if (socketChannel.connect(new InetSocketAddress(serverHost, serverPort))) {
            //连接成功，可以发送信息
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else {
            //如果连接失败则给一个连接操作位，让它轮询
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        }
    }

    /**
     * 发送消息
     *
     * @param channel 当前管道
     */
    private void sendMessage(SocketChannel channel) throws IOException {

        System.out.print("You Say: ");
        Scanner sc = new Scanner(System.in);
        String message = sc.nextLine(); //发送内容
        writeMessage(channel,message);

    }

    private void writeMessage(SocketChannel channel, String message) throws IOException {
        String[] tos = message.split("to");
        if (tos.length == 0) {
            System.out.println("please input send where by to [username] ");
            return;
        }
        message = message + "&" + " from " + fromName + " to "+ tos[tos.length - 1] ;
        byte[] bytes = message.getBytes();
        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
        writeBuffer.put(bytes);
        writeBuffer.flip();
        channel.write(writeBuffer);
        if (!writeBuffer.hasRemaining()) {
            System.out.println("send message success at " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    }


    @Override
    public void run() {
        try {
            connectServer();
            while (!stop) {
                selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                SelectionKey key;
                while (iterator.hasNext()) {
                    key = iterator.next();
                    iterator.remove();
                    handleReceiveMessage(key);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        if (selector != null) {
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
